import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
import 'dart:math';

typedef ColorChangeStart<T> = void Function(T color);
typedef ColorChange<T> = void Function(T color);
typedef ColorChangeEnd = void Function();
typedef OnCancel = void Function();

class CircleColorPicker extends StatelessWidget{

  static List<Color> colors = [
    Color(0xFFFF0000),
    Color(0xFFFF00FF),
    Color(0xFF0000FF),
    Color(0xFF00FFFF),
    Color(0xFF00FF00),
    Color(0xFFFFFF00),
    Color(0xFFFF0000)
  ];

  final double width;
  final double height;
  final double strokeWidthScale;

  final ColorChangeStart<Color> onChangeStart;
  final ColorChange<Color> onChange;
  final ColorChangeEnd onChangeEnd;
  final OnCancel onCancel;

  const CircleColorPicker({
    Key key,
    this.width = 200,//提供默认值200
    this.height = 200,
    this.strokeWidthScale = 0.2,
    this.onChangeStart,
    this.onChange,
    this.onChangeEnd,
    this.onCancel
  }) : assert(width != null),
        assert(height != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {

    double minValue = min(width, height);

    double strokeWidth = minValue*strokeWidthScale;
    double outCircleRadius = minValue/2; //圆环外部半径
    double innerCircleRadius = outCircleRadius - strokeWidth; //圆环内部半径

    return new GestureDetector(

      onPanStart: (details){

        RenderBox box = context.findRenderObject();
        Offset offset = box.localToGlobal(Offset.zero);
        double dx = offset.dx;
        double dy = offset.dy;

        double x = details.globalPosition.dx;
        double y = details.globalPosition.dy;

        double currentX = x - dx - this.width/2;
        double currentY = y - dy - this.height/2;

        bool isInColorCircle = inColorCircle(currentX, currentY, outCircleRadius, innerCircleRadius);

//        print(isInColorCircle ? "在圆环上" : "不在圆环上");

        if(isInColorCircle){

          double angle = atan2(currentY, currentX);
          double unit = angle / (2 * pi);

          if (unit < 0) {

            unit += 1;
          }

          Color color = interCircleColor(unit);

          if(onChangeStart!=null){

            onChangeStart(color);

          }

        }

      },

      onPanUpdate: (details){

        RenderBox box = context.findRenderObject();
        Offset offset = box.localToGlobal(Offset.zero);
        double dx = offset.dx;
        double dy = offset.dy;

        double x = details.globalPosition.dx;
        double y = details.globalPosition.dy;

        double currentX = x - dx - this.width/2;
        double currentY = y - dy - this.height/2;

        bool isInColorCircle = inColorCircle(currentX, currentY, outCircleRadius, innerCircleRadius);

//        print(isInColorCircle ? "在圆环上" : "不在圆环上");

        if(isInColorCircle){

          double angle = atan2(currentY, currentX);
          double unit = angle / (2 * pi);

          if (unit < 0) {

            unit += 1;
          }

          Color color = interCircleColor(unit);

          if(onChange!=null){

            onChange(color);

          }

        }

      },

      onPanEnd: (details){

        if(onChangeEnd!=null){

          onChangeEnd();
        }

      },

      onPanCancel: (){

        print("取消移动");
        if(onCancel!=null){

          onCancel();
        }

      },

      child: new CustomPaint(

        painter: new CircleColorPainter(
            colors: colors,
            bgColor: Colors.grey,
            strokeWidth: strokeWidth,
            outCircleRadius: outCircleRadius,
            innerCircleRadius: innerCircleRadius,
        ),
        size: Size(width, height),
      ),
    );
  }

  bool inColorCircle(double x, double y, double outRadius,
      double inRadius) {

    double outCircle = pi * outRadius * outRadius;
    double inCircle = pi * inRadius * inRadius;
    double fingerCircle = pi * (x * x + y * y);

    return fingerCircle < outCircle && fingerCircle > inCircle;
  }

  Color interCircleColor(double unit){

    if (unit <= 0) {
      return colors[0];
    }
    if (unit >= 1) {
      return colors[colors.length - 1];
    }

    double p = unit * (colors.length - 1);
    int i =  p.toInt();
    p -= i;

    // now p is just the fractional part [0...1) and i is the index
    Color c0 = colors[i];
    Color c1 = colors[i + 1];
    int a = ave(c0.alpha, c1.alpha, p);
    int r = ave(c0.red, c1.red, p);
    int g = ave(c0.green, c1.green, p);
    int b = ave(c0.blue, c1.blue, p);

    return Color.fromARGB(a, r, g, b);
  }

  int ave(int s, int d, double p) {

    return s + (p * (d - s)).round();
  }

}

class CircleColorPainter extends CustomPainter{

  final List<Color> colors;
  final Color bgColor;
  final double strokeWidth;
  final double outCircleRadius;
  final double innerCircleRadius;

  const CircleColorPainter({
    @required this.colors,
    this.bgColor,
    @required this.strokeWidth,
    @required this.outCircleRadius,
    @required this.innerCircleRadius,
  }) : super();


  @override
  void paint(Canvas canvas, Size size) {

    double drawCircleRadius = outCircleRadius - strokeWidth/2;//要绘制的圆环的半径

    Offset centerPoint = new Offset(size.width/2, size.height/2) ;

    if (bgColor != null ){

      canvas.drawRect(Rect.fromPoints(Offset(0, 0), Offset(size.width, size.height)),
          Paint()..color = bgColor..style = PaintingStyle.fill);

    }

    final Rect arcRect = Rect.fromCircle(center: centerPoint, radius: drawCircleRadius);

    final Gradient gradient = SweepGradient(
      center: FractionalOffset.center,
      startAngle: 0.0,
      endAngle: pi * 2,
      colors: colors,
//      stops: const <double>[0.0, 0.25, 0.5, 0.75, 1.0],
    );
    final progressPaint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = strokeWidth
      ..isAntiAlias = true
      ..shader = gradient.createShader(arcRect);

    canvas.drawCircle(centerPoint,drawCircleRadius, progressPaint);

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {

//    print("shouldRepaint");

    return true;
  }

}